home *** CD-ROM | disk | FTP | other *** search
- {
- I've posted a working util that lists the Device Drivers that are resident in
- memory. It uses the header record to point to the next driver in the chain
- and "walks" the memory chain until an offset end flag is reached. Hope you
- enjoy it and that it isn't too sloppy. At the end, I have a question that
- needs to be answered if you're interested....
- }
-
- program DevList;
-
- { this program walks the device driver memory chain. Each device
- driver points to the next until the ENDFLAG is reached. I use
- the popular undocumented DOS function $52 to jump to the DOS
- "List of Lists" then $22 bytes beyond that, the first device in
- the chain (NUL) can be found.
-
- Thanks to Ralf Brown and his valuable MS DOS Interrupts List,
- to Timo Salmi, and to the person(?) who wrote the cool
- hex-to-string conversion functions that I use all the time.
- }
-
- {$M 8192,0,0}
-
- uses
- DOS;
-
- type
- pstrg = string[9]; { pointer conversion format }
-
- Array8C = array [1..8] of char; { for device and file names }
-
- DevRec = record
- NextDev_ofs : word; {pointer to next device header, offset value}
- NextDev_seg : word; {pointer to next device header, segment value}
- Attributes : word; {Attributes: block or char, IOCTL, etc.}
- Strategy : word; {pointer to device strategy routine, offset}
- Interrupt : word; {pointer to device interrupt routine, offset}
- NameDev : Array8C; {Name if char, or units if block}
- end;
- DevPtr = ^DevRec;
-
- DevFileRec = record
- FileName : Array8C;
- end;
- DevFilePtr = ^DevFileRec;
-
- const
- LOL_HEADDEV_NUL = $22; { offset from "List of Lists"
- to NUL device header }
- FNAME = $8;
- ENDFLAG = $FFFF;
- STDDEVS : array [1..12] of Array8C =
- ('NUL ', 'CON ', 'AUX ', 'PRN ',
- 'CLOCK$ ', 'COM1 ', 'COM2 ', 'COM3 ',
- 'COM4 ', 'LPT1 ', 'LPT2 ', 'LPT3 ');
-
- var
- r : registers;
- i, { index }
- Adjust : byte;
- Header : DevPtr;
- DevFile : DevFilePtr;
- Valid,
- Done : boolean;
-
-
- function BinW(Decimal : word) : string;
- const
- BINDIGIT : array [0..1] of char = '01';
- var
- i : byte;
- Binar : string;
- begin
- fillchar (binar, sizeof(Binar), ' ');
- Binar [0] := chr(16);
- for i := 0 to 15 do
- Binar[16-i] := BINDIGIT[(Decimal shr i) and 1];
- BinW := Binar;
- end;
-
-
- function HexN (b : byte) : char; { convert nibble to char }
- begin
- b := b and 15; { forces to only 4 bits }
- if b > 9 then
- inc(b,7); { adjust for hex digits };
- HexN := chr(b+48); { convert to character }
- end;
-
-
- function HexB(b : byte) : string;
- begin
- HexB := HexN (b shr 4) + HexN (b); { assemble the nibbles }
- end;
-
-
- function HexW(w : word) : string;
- begin
- {$R-}
- hexw := HexB(w shr 8) + HexB(w); { assemble the bytes }
- {$R+}
- end;
-
-
- function HexL(l : longint) : string;
- begin
- HexL := HexW(l shr 16) + HexW(l); { assemble the words }
- end;
-
-
- function XP(p : pointer) : pstrg; { display pointer P }
- begin
- XP := HexW(seg(p^)) + ':' + HexW(ofs(p^));
- end;
-
- begin
- assign(output, '');
- rewrite(output); { allow command line redirection }
- writeln('Device':0, 'Address':12, 'Strat':10, 'Intrpt':8,
- 'Attrib':10, 'File Name':23);
- for i := 1 to 69 do
- write('-');
- writeln;
-
- with r do
- begin
- es := 0;
- bx := 0;
- ah := $52;
- { this is an undocumented DOS function call:
- Get pointer to DOS "List of Lists" }
- msdos (r);
- { es and bx now have values }
- if (es = 0) and (bx = 0) then
- halt(0);
-
- Header := ptr(es, bx + LOL_HEADDEV_NUL); { we get NUL dev from this }
- end; {with}
-
- Done := FALSE; { dummy variable to keep the repeat loop going,
- otherwise would have to duplicate the output
- routines one more time for the final device. }
- repeat
- with Header^ do
- begin
- Adjust := 0;
- { adjust keeps display columns aligned, bit 15 set is a Character
- device, if clear it is a Block device and 1st byte is # of block
- devs supported}
-
- if boolean ((Attributes shr 15) and 1) = TRUE then
- write (NameDev)
- else
- begin
- write ('BLKdev=', byte (NameDev[1]));
- Adjust := byte (NameDev[1]) div 10;
- end;
-
- write(XP(Header) : 12 - Adjust);
- write(HexW(Strategy) : 7);
- write(HexW(Interrupt) : 7);
- write(HexW(Attributes) : 7, '=');
- write(BinW(Attributes));
-
- { this next section I can't find documented anywhere, but I observed it
- and decided to include it anyway, with MSDOS v5.0, others are unknown.
- The file name's extension isn't saved and doesn't matter, either. }
-
- if ofs(Header^) < FNAME then
- { "borrow" from the segment and give it to the offset }
- DevFile := ptr(seg(Header^) - $1, ofs(Header^) + $10 - FNAME)
- else
- DevFile := ptr(seg(Header^), ofs(Header^) - FNAME);
-
- Valid := TRUE;
- for i := 1 to 12 do
- if DevFile^.FileName = STDDEVS[i] then
- Valid := FALSE;
-
- if Valid then
- for i := 1 to 8 do
- if not (DevFile^.Filename[i] in [' '..'z']) then
- Valid := FALSE;
-
- if {still} Valid then
- write (' ', DevFile^.FileName);
-
- writeln;
- if NextDev_ofs = ENDFLAG then
- exit; { end of the device chain }
-
- Header := ptr(NextDev_seg, NextDev_ofs);
-
- end; {with}
- until Done;
- end.
- {
- The question: I have seen utils that do this actually give the size of
- the driver in memory. MSD and PMap both do this. Does anybody know
- how I can determine the size of the driver in memory?
- }